#include <algorithm>

#include "changes_manager.h"

void ChangesManager::push(Elements::ElementType type, unsigned id)
{
    std::unique_lock lock(m_locker);
    for (auto& pair : m_sessionChanges)
        pair.second[type].insert(id);
}

void ChangesManager::push(Elements::ElementType type, std::vector<unsigned> ids)
{
    std::unique_lock lock(m_locker);
    for (auto& pair : m_sessionChanges)
        pair.second[type].insert(ids.begin(), ids.end());
}

Api::Changes ChangesManager::pop(const Uuids::Uuid& sessionUuid)
{
    std::unique_lock lock(m_locker);
    if (0 == m_sessionChanges.count(sessionUuid))
        return {};

    const auto result = m_sessionChanges.at(sessionUuid);
    m_sessionChanges[sessionUuid] = {};
    return result;
}

void ChangesManager::erase(
    const Uuids::Uuid& sessionUuid,
    Elements::ElementType type,
    unsigned id
)
{
    std::unique_lock lock(m_locker);
    if (0 == m_sessionChanges.count(sessionUuid))
        return;

    auto& changes = m_sessionChanges.at(sessionUuid);
    if (0 != changes.count(type))
        changes.at(type).erase(id);
}

void ChangesManager::erase(
    const Uuids::Uuid& sessionUuid,
    Elements::ElementType type,
    const std::vector<unsigned>& ids
)
{
    std::unique_lock lock(m_locker);
    if (0 == m_sessionChanges.count(sessionUuid))
        return;

    auto& changes = m_sessionChanges.at(sessionUuid);
    if (0 == changes.count(type))
        return;

    auto idsBegin = ids.begin();
    auto idsEnd = ids.end();

    auto& items = changes.at(type);
    auto itemsBegin = items.begin();
    auto itemsEnd = items.end();

    for (auto it = itemsBegin; it != itemsEnd;)
    {
        if (std::find(idsBegin, idsEnd, *it) != idsEnd)
            it = items.erase(it);
        else
            ++it;
    }

    // Удаление типа элемента, если перечень идентификаторов пуст.
    for (auto it = changes.begin(); it != changes.end();)
    {
        if (it->second.empty())
            it = changes.erase(it);
        else
            ++it;
    }
}

void ChangesManager::addSession(const Uuids::Uuid& sessionUuid)
{
    std::unique_lock lock(m_locker);
    m_sessionChanges[sessionUuid] = {};
}

void ChangesManager::removeSession(const Uuids::Uuid& sessionUuid)
{
    std::unique_lock lock(m_locker);
    m_sessionChanges.erase(sessionUuid);
}
